#include <QStringList>
#include <QVariant>
#include "container-helper.h"

StringNumericalLess::StringNumericalLess (Qt::CaseSensitivity caseSensitivity, bool localeAware)
    : m_caseSensitivity(caseSensitivity), m_localeAware(localeAware)
{
}

bool StringNumericalLess::operator() (QString left, QString right) const
{
    int leftPosition = 0;
    int rightPosition = 0;

    while (true)
    {
        if (leftPosition >= left.size() || rightPosition >= right.size())
        {
            if (left.isEmpty())
                return !right.isEmpty();
            else if (right.isEmpty())
                return false;
            else
                return left.size() < right.size();
        }

        QChar leftCharacter = left.at(leftPosition);
        QChar rightCharacter = right.at(rightPosition);
        bool isLeftDigit = leftCharacter.isDigit();
        bool isRightDigit = rightCharacter.isDigit();
        if (isLeftDigit || isRightDigit)
        {
            // one of the characters is a digit
            if (!(isLeftDigit && isRightDigit))
            {
                // one of the characters is not digit, so compare them normally (they are not equal)
                Q_ASSERT(leftCharacter != rightCharacter);
                if (m_caseSensitivity == Qt::CaseInsensitive)
                {
                    leftCharacter = leftCharacter.toLower();
                    rightCharacter = rightCharacter.toLower();
                }
                if (m_localeAware)
                    return QString::localeAwareCompare(leftCharacter, rightCharacter) < 0;
                else
                    return leftCharacter < rightCharacter;
            }
            else
            {
                // both characters are digits, so compare numbers that they create
                QPair<int,int> leftNumberAndZeroes = numberFrom(left, leftPosition);
                QPair<int,int> rightNumberAndZeros = numberFrom(right, rightPosition);
                if (leftNumberAndZeroes.first < rightNumberAndZeros.first)
                {
                    return true;
                }
                else if (leftNumberAndZeroes.first > rightNumberAndZeros.first)
                {
                    return false;
                }
                else
                {
                    // both numbers are equal, but the one with more leading zeroes is considered smaller
                    if (leftNumberAndZeroes.second > rightNumberAndZeros.second)
                    {
                        return true;
                    }
                    else if (leftNumberAndZeroes.second < rightNumberAndZeros.second)
                    {
                        return false;
                    }
                    else
                    {
                        // the leading zeroes are equal, so continue with shifted positions
                        Q_ASSERT((QString::number(leftNumberAndZeroes.first).size() + leftNumberAndZeroes.second)
                                 == QString::number(rightNumberAndZeros.first).size() + rightNumberAndZeros.second);
                        int numberSize = QString::number(leftNumberAndZeroes.first).size() + leftNumberAndZeroes.second;
                        leftPosition += numberSize;
                        rightPosition += numberSize;
                    }
                }
            }
        }
        else
        {
            // none of the characters is a digit, so compare them normally (they can be equal)
            if (m_caseSensitivity == Qt::CaseInsensitive)
            {
                leftCharacter = leftCharacter.toLower();
                rightCharacter = rightCharacter.toLower();
            }
            int result;
            if (m_localeAware)
                result = QString::localeAwareCompare(leftCharacter, rightCharacter);
            else
                result = QString(leftCharacter).compare(rightCharacter);

            if (result < 0)
            {
                return true;
            }
            else if (result > 0)
            {
                return false;
            }
            else
            {
                leftPosition++;
                rightPosition++;
            }
        }
    }

}

QPair<int,int> StringNumericalLess::numberFrom (const QString& text, int position)
{
    QString number;
    for (; position < text.size(); position++)
    {
        if (text.at(position).isDigit())
            number.append(text.at(position));
        else
            break;
    }

    int leadingZeros = 0;
    for (int i = 0; i < number.size(); i++)
    {
        if (number.at(i) == '0')
            leadingZeros++;
        else
            break;
    }

    return qMakePair(number.toInt(), leadingZeros);
}

bool compareVariants (QVariant first, QVariant second)
{
    return (first.isNull() == second.isNull()) && (first == second);
}
